const _ = require("lodash");
const {
  readAllValues,
} = require("../awakened-potential/helpers/readAllValues.js");

/**
 * 构建一阶马尔科夫转移概率矩阵
 */
function buildMarkovMatrix(history) {
  const matrix = Array.from({ length: 50 }, () => Array(50).fill(0));

  for (let i = 1; i < history.length; i++) {
    const prev = Number(history[i - 1].number);
    const curr = Number(history[i].number);
    if (prev >= 1 && curr >= 1 && prev <= 49 && curr <= 49) {
      matrix[prev][curr]++;
    }
  }

  for (let i = 1; i <= 49; i++) {
    const row = matrix[i];
    const sum = row.reduce((a, b) => a + b, 0);
    if (sum > 0) {
      for (let j = 1; j <= 49; j++) {
        row[j] = row[j] / sum;
      }
    }
  }

  return matrix;
}

/**
 * 获取热冷号
 */
function predictHotCold(history, hotCount = 16, coldCount = 16) {
  const countMap = Array(50).fill(0);

  for (const item of history) {
    const number = Number(item.number);
    if (number >= 1 && number <= 49) {
      countMap[number]++;
    }
  }

  const result = countMap.map((count, number) => ({ number, count })).slice(1);
  const hot = _.orderBy(result, ["count", "number"], ["desc", "asc"]).map((item) => item.number);
  const cold = _.orderBy(result, ["count", "number"], ["asc", "asc"]).map((item) => item.number);
  return { hot, cold };
}

/**
 * 获取最终预测（马尔科夫为主，补足热冷号）
 */
function getMarkovPredictionWithFallback(prev, matrix, windowData, totalLimit = 32) {
  const row = matrix[prev];
  if (!row) return [];

  const sorted = row
    .map((prob, number) => ({ number, prob }))
    .slice(1)
    .filter((item) => item.prob > 0)
    .sort((a, b) => b.prob - a.prob)
    .map((item) => item.number);

  let baseSet = _.uniq(sorted);
  if (baseSet.length > totalLimit) {
    return baseSet.slice(0, totalLimit).sort((a, b) => a - b);
  }

  const { hot, cold } = predictHotCold(windowData);
  const half = Math.ceil((totalLimit - baseSet.length) / 2);
  const fillHot = hot.filter((n) => !baseSet.includes(n)).slice(0, half);
  const fillCold = cold.filter((n) => !baseSet.includes(n) && !fillHot.includes(n)).slice(0, totalLimit - baseSet.length - fillHot.length);

  baseSet = _.uniq([...baseSet, ...fillHot, ...fillCold]);
  return baseSet.slice(0, totalLimit).sort((a, b) => a - b);
}

/**
 * 连续段落分析
 */
function analyzeStreaks(arr) {
  let streaks1 = [], streaks0 = [];
  let current = arr[0], count = 1;

  for (let i = 1; i < arr.length; i++) {
    if (arr[i] === current) count++;
    else {
      (current === 1 ? streaks1 : streaks0).push(count);
      current = arr[i];
      count = 1;
    }
  }
  (current === 1 ? streaks1 : streaks0).push(count);

  const maxStreak1 = Math.max(...streaks1, 0);
  const maxStreak0 = Math.max(...streaks0, 0);

  return {
    maxStreak1,
    maxStreak0,
    avgStreak1: (streaks1.reduce((a, b) => a + b, 0) / streaks1.length || 0).toFixed(2),
    avgStreak0: (streaks0.reduce((a, b) => a + b, 0) / streaks0.length || 0).toFixed(2),
    streaks1,
    streaks0,
  };
}

// ========== ✅ 主程序入口 ==========

const historyDataRaw = readAllValues("m");
const historyData = historyDataRaw.map((item) => ({
  time: item.time,
  number: Number(item.number),
}));

const windowSize = 100;
const predictionCount = 32;

let correct = 0;
let wrong = 0;
let hitArray = [];

console.log(`\n🧠 一阶马尔科夫链 + 热冷补足（窗口大小：${windowSize}），共 ${historyData.length - windowSize} 次：\n`);

for (let i = windowSize; i < historyData.length; i++) {
  const actual = historyData[i];
  const prevNumber = historyData[i - 1].number;
  const windowData = historyData.slice(i - windowSize, i);

  const matrix = buildMarkovMatrix(historyData.slice(0, i));
  const prediction = getMarkovPredictionWithFallback(prevNumber, matrix, windowData, predictionCount);

  const hit = prediction.includes(actual.number);
  hitArray.push(hit ? 1 : 0);
  hit ? correct++ : wrong++;

  console.log(`📅 第${i + 1}期（${actual.time}）`);
  console.log(`🎯 推荐(${prediction.length}):`, prediction.join(", "));
  console.log(`✅ 实际号码: ${actual.number} → 是否命中: ${hit ? "✅ 是" : "❌ 否"}`);
  console.log("---------------------------------------------------\n");
}

// ✅ 汇总统计
const { maxStreak1, maxStreak0, avgStreak1, avgStreak0, streaks1, streaks0 } = analyzeStreaks(hitArray);
const accuracy = ((correct / (correct + wrong)) * 100).toFixed(2);

console.log("\n🎯 预测结果统计");
console.log(`总预测期数: ${correct + wrong}`);
console.log(`✅ 命中期数: ${correct}`);
console.log(`❌ 错误期数: ${wrong}`);
console.log(`📊 命中率: ${accuracy}%`);

console.log("\n📈 连续预测表现分析：");
console.log(`✅ 最大连续命中次数: ${maxStreak1}`);
console.log(`❌ 最大连续失败次数: ${maxStreak0}`);
console.log(`✅ 成功段落数量: ${streaks1.length}`);
console.log(`❌ 错误段落数量: ${streaks0.length}`);
console.log(`✅ 成功段落平均长度: ${avgStreak1}`);
console.log(`❌ 错误段落平均长度: ${avgStreak0}`);